package top.jiangqiang.qyblog.core.service.impl;

import cn.hutool.core.util.StrUtil;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.jiangqiang.qyblog.common.base.query.PageResult;
import top.jiangqiang.qyblog.common.base.response.Result;
import top.jiangqiang.qyblog.common.exception.JsonException;
import top.jiangqiang.qyblog.core.base.service.impl.BaseServiceImpl;
import top.jiangqiang.qyblog.core.constant.StorageTypeEnum;
import top.jiangqiang.qyblog.core.domain.StorageProperties;
import top.jiangqiang.qyblog.core.domain.StoragePropertiesUpdateDto;
import top.jiangqiang.qyblog.core.domain.dto.StorageAddDto;
import top.jiangqiang.qyblog.core.domain.dto.StorageQueryDto;
import top.jiangqiang.qyblog.core.domain.dto.StorageUpdateDto;
import top.jiangqiang.qyblog.core.domain.entity.File;
import top.jiangqiang.qyblog.core.domain.entity.Storage;
import top.jiangqiang.qyblog.core.domain.vo.StorageVo;
import top.jiangqiang.qyblog.core.mapper.StorageMapper;
import top.jiangqiang.qyblog.core.service.IFileService;
import top.jiangqiang.qyblog.core.service.IStorageService;
import top.jiangqiang.qyblog.core.storage.impl.S3AsyncStorageClient;

/**
 * <p>
 * 存储器 服务实现类
 * </p>
 *
 * @author JiangQiang
 * @since 2023-05-22
 */
@Service
public class StorageServiceImpl extends BaseServiceImpl<StorageMapper, Storage> implements IStorageService {
    private final IFileService fileService;

    //解决循环依赖
    public StorageServiceImpl(@Lazy IFileService fileService) {
        this.fileService = fileService;
    }

    @Override
    public Result<StorageTypeEnum[]> getTypes() {
        return Result.ok(StorageTypeEnum.values());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> addStorage(StorageAddDto storageAddDto) {
        Storage storage = typeConverter.convert(storageAddDto, Storage.class);
        if (StrUtil.isBlank(storage.getName())) {
            storage.setName(storage.getType().getName());
        }
        //校验配置是否可用
        if (validateConfig(storage)) {
            Long count = lambdaQuery().count();
            //仅第一次新增，设置为默认存储器
            storage.setActive(count == 0);
            save(storage);
            return Result.ok();
        } else {
            return Result.error("存储器配置无效");
        }
    }

    @Override
    public Result<String> editStorage(StorageUpdateDto storageUpdateDto) {
        Storage storage = baseMapper.selectById(storageUpdateDto.getId());
        if (storage == null) {
            return Result.error("存储器不存在");
        } else {
            storage.setName(storageUpdateDto.getName());
            StorageProperties storageProperties = storage.getConfig();
            StoragePropertiesUpdateDto storageUpdateDtoConfig = storageUpdateDto.getConfig();
            storageProperties.setAccessKey(storageUpdateDtoConfig.getAccessKey());
            storageProperties.setAccessSecret(storageUpdateDtoConfig.getAccessSecret());
            if (validateConfig(storage)) {
                baseMapper.updateById(storage);
                return Result.ok();
            } else {
                return Result.error("存储器配置无效");
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized Result<String> activeStorage(Long id) {
        Storage storage = baseMapper.selectById(id);
        if (storage != null) {
            if (storage.getActive()) {
                return Result.error("当前存储器已经设为默认存储器");
            } else {
                //失活所有存储器
                lambdaUpdate().set(Storage::getActive, false).update();
                storage.setActive(true);
                baseMapper.updateById(storage);
                return Result.ok();
            }
        } else {
            return Result.error("存储器不存在");
        }
    }

    @Override
    public Storage getActiveStorage() {
        return lambdaQuery().eq(Storage::getActive, true).one();
    }

    @Override
    public Result<Boolean> deleteStorage(Long id) {
        Long count = fileService.lambdaJoinWrapper().eq(File::getStorageId, id).count();
        if (count > 0) {
            return Result.error("存储器已经被使用，无法删除");
        } else {
            Storage storage = baseMapper.selectById(id);
            if (storage != null) {
                if (storage.getActive()) {
                    return Result.error("默认存储策略无法删除");
                } else {
                    return Result.ok(removeById(id));
                }
            } else {
                return Result.error("存储器不存在");
            }
        }
    }

    @Override
    public @NotNull Storage getStorage(Long storageId) {
        Storage storage;
        if (storageId == null) {
            storage = getActiveStorage();
        } else {
            storage = getById(storageId);
        }
        if (storage == null) {
            //理论上只要不是第一次使用，不可能走到这里
            throw new JsonException("不存在可用的存储器");
        }
        return storage;
    }

    @Override
    public Result<StorageVo> getStorageDetail(Long id) {
        return Result.ok(getById(id, StorageVo.class));
    }

    @Override
    public PageResult<StorageVo> findByCondition(StorageQueryDto query) {
        return lambdaJoinWrapper().like(StrUtil.isNotBlank(query.getName()), Storage::getName, query.getName())
                .orderByDesc(File::getCreateTime).page(query.toPage(), StorageVo.class);
    }

    /**
     * 校验配置是否可用
     *
     * @param storage 存储器配置
     * @return true可用
     */
    private boolean validateConfig(Storage storage) {
        if (storage == null) {
            return false;
        }
        StorageTypeEnum type = storage.getType();
        return switch (type) {
            case LOCAL -> throw new JsonException("暂时不支持本地存储");
            case S3 -> S3AsyncStorageClient.test(storage.getConfig());
        };
    }
}
